# -*- coding: utf-8 -*-
from typing import Dict, Any, Tuple
from collections import deque
import numpy as np
import time

from recognition.actions.base import BaseAction
from common.landmarks import LMS
from common.config import (
    WAVE_WINDOW_S, WAVE_MIN_REVERSALS, WAVE_MIN_AMPLITUDE_SHOULDER,
    VIS_THRESH
)

class WaveAction(BaseAction):
    label = "wave"

    def score(self, lms, person_id: int, get_state) -> Tuple[float, Dict[str, Any]]:
        """
        时序打分：
        - 维护左右手腕 x 的时间窗口 deque: [(t, x_norm), ...]
        - 计算反转次数 reversals 与振幅 amplitude
        - 综合一个瞬时高度加成（腕高于肩）
        """
        st = get_state(person_id)
        # state keys:
        dq_left  = st.setdefault("wave_left_hist", deque())
        dq_right = st.setdefault("wave_right_hist", deque())

        # 关节点与可见性
        lw = lms[LMS.LEFT_WRIST];  rw = lms[LMS.RIGHT_WRIST]
        ls = lms[LMS.LEFT_SHOULDER]; rs = lms[LMS.RIGHT_SHOULDER]

        def ok(p): return getattr(p, "visibility", 0.0) >= VIS_THRESH
        t_now = time.time()

        # 仅在可见时更新历史
        if ok(lw) and ok(ls):
            # 使用“相对肩中心”的归一化（无法直接得肩宽像素，这里近似用归一化坐标直接用 x）
            # 如果你在 vision 层提供像素和肩中心/肩宽，可替换为真实归一化
            dq_left.append((t_now, float(lw.x)))
        if ok(rw) and ok(rs):
            dq_right.append((t_now, float(rw.x)))

        # 窗口裁剪
        def trim(dq):
            while dq and (t_now - dq[0][0]) > WAVE_WINDOW_S:
                dq.popleft()
        trim(dq_left); trim(dq_right)

        # 计算反转与幅度
        def reversals_and_amp(dq):
            if len(dq) < 5:
                return 0, 0.0
            xs = np.array([x for _, x in dq], dtype=np.float32)
            dx = np.diff(xs)
            signs = np.sign(dx)
            signs[np.abs(dx) < 1e-4] = 0
            rev, last = 0, 0
            for s in signs:
                if s == 0:
                    continue
                if last == 0:
                    last = s
                elif s != last:
                    rev += 1
                    last = s
            amp = float(xs.max() - xs.min())
            return rev, amp

        rev_l, amp_l = reversals_and_amp(dq_left)
        rev_r, amp_r = reversals_and_amp(dq_right)

        # 核心时序分：取左右最大
        def seq_score(rev, amp):
            # 目标：rev >= MIN_REVERSALS 且 amp >= MIN_AMP → 分近 1
            sr = min(1.0, rev / max(1.0, float(WAVE_MIN_REVERSALS)))
            sa = min(1.0, amp / max(1e-6, float(WAVE_MIN_AMPLITUDE_SHOULDER)))
            return 0.6 * min(sr, sa) + 0.4 * max(sr, sa)

        seq_left  = seq_score(rev_l, amp_l)
        seq_right = seq_score(rev_r, amp_r)
        seq = max(seq_left, seq_right)

        # 瞬时高度加成
        inst_left = max(0.0, (ls.y - lw.y) * 2.0) if (ok(lw) and ok(ls)) else 0.0
        inst_right= max(0.0, (rs.y - rw.y) * 2.0) if (ok(rw) and ok(rs)) else 0.0
        inst = max(inst_left, inst_right)
        inst = float(np.clip(inst, 0.0, 1.0))

        # 融合：时序权重更高
        score = 0.75 * seq + 0.25 * inst
        return float(np.clip(score, 0.0, 1.0)), {}